package icasue.reflect.adaptor;


import lombok.SneakyThrows;
import icasue.reflect.annotations.NotNull;
import icasue.reflect.annotations.Nullable;
import icasue.reflect.handles.method.MethodOF;
import icasue.reflect.handles.predicate.SureOF;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @Author: Qiao Hang
 * @CreateDate: 2021/9/28 上午10:26
 * @UpdateDate:
 * @Description: 该类用于适配某些可能存在的模块，如果存在依赖模块，则在包handles.下的类中进行适配与增强.
 */
abstract class AdaptorModel {

    // 静态属性用于表示是否模块被加载.
    private static final Map<String,AtomicReference<Boolean>> modelLoaded = new ConcurrentHashMap<>();

    // 返回适配的类全类名(如果模块被加载)
    @NotNull
    public abstract String classReflectAble();

    // 返回适配的类(如果模块被加载), 否则null.
    @Nullable
    public final Optional<Class<?>> type(){
        Optional<Class<?>> type = null;
        if(modelIfLoad()){
            try {
                type = Optional.ofNullable(Class.forName(classReflectAble()));
            }catch (Throwable e){ }
            SureOF.notNull_.accept(type);
        }
        return type;
    };

    // 返回适配的类实例的某个属性值(如果模块被加载), 否则为null
    @Nullable
    @SneakyThrows(Throwable.class)
    public final <Res> Optional<Res> fieldGet(String fieldName, @Nullable Object inst, Class<Res> rType){
        Optional<Res> result = null;
        if(modelIfLoad()){
            Field field = type().get().getDeclaredField(fieldName);
            field.setAccessible(true);
            result = Optional.ofNullable((Res)field.get(inst));
        }
        return result;
    };

    // 设置适配的类实例的某个属性值(如果模块被加载), 否则为null
    @Nullable
    @SneakyThrows(Throwable.class)
    public final Optional<Boolean> fieldSet(String fieldName, @Nullable Object inst, Object val){
        Optional<Boolean> result = null;
        if(modelIfLoad()){
            Field field = type().get().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(inst,val);
            result = Optional.ofNullable(Boolean.TRUE);
        }
        return result;
    };


    // 调用适配模块目标类的某个方法(如果模块被加载), 否则为null
    @Nullable
    @SneakyThrows(Throwable.class)
    public final <Res> Optional<Res> exec(String methodName, @Nullable Object inst, Object[] values, Class<Res> rType){
        Optional<Res> result = null;
        if(modelIfLoad()){
            result = Optional.ofNullable(
                    (Res) MethodOF.invoke_mType_mName_inst_paramArray.apply(type().get(),methodName,inst,values)
            );
        }
        return result;
    }

    // 该方法用于初始化模块是否被初始化的标记变量 modelLoaded.
    @NotNull
    public final Boolean modelIfLoad(){
        String type = classReflectAble();
        if(type == null){
            return Boolean.FALSE;
        }

        if(modelLoaded.containsKey(type))
            return modelLoaded.get(type).get();

        AtomicReference<Boolean> loadedOrNot =
                new AtomicReference(Boolean.FALSE);
        try {
            Class.forName(type);
            loadedOrNot.set(Boolean.TRUE);
        }catch (Throwable e){
            loadedOrNot.set(Boolean.FALSE);
        }finally {
            modelLoaded.put(type,loadedOrNot);
        }
        return loadedOrNot.get();
    }
}